#include <stdio.h>
#include <stdlib.h>
#include <dos.h>
#include <conio.h>
#include <string.h>
#include "gui.h"

//设置显示模式为80*25 16色文本模式，顺带清屏
void SetTextMode()
{
    _AX = 3;
    geninterrupt(0x10);
}

//禁止背景闪烁，改为高亮背景色
void DisableBlink()
{
    _AX = 0x1003;
    _BL = 0;
    geninterrupt(0x10);
}

//隐藏光标
void HideCursor()
{
    _AH = 1;
    _CH = 32;
    geninterrupt(0x10);
}

//显示光标
void ShowCursor()
{
    _AH = 1;
    _CX = 0x0607;
    geninterrupt(0x10);
}

//字符点阵表
char charsmap1[4 * 16] = {
    //地雷符号，占2个字符，安装在0xE、0xF位置
    0x00, 0x00, 0x01, 0x11, 0x0B, 0x05, 0x0B, 0x3F,
    0x0F, 0x07, 0x0B, 0x11, 0x01, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x10, 0xA0, 0xC0, 0xE0, 0xFC,
    0xE0, 0xC0, 0xA0, 0x10, 0x00, 0x00, 0x00, 0x00,
    //[=]符号，占2个字符，安装在0x10、0x11位置
    0xFF, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0xE1,
    0xE1, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0xFF,
    0xFF, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x8F,
    0x8F, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xFF
};
char charsmap2[4 * 16] = {
    //Email图标，占2个字符，安装在字符01、02位置
    0x00, 0x00, 0x7F, 0x40, 0x60, 0x58, 0x46, 0x41,
    0x40, 0x40, 0x40, 0x40, 0x7F, 0x00 ,0x00, 0x00,
    0x00, 0x00, 0xFE, 0x02, 0x06, 0x1A, 0x62, 0x82,
    0x02, 0x02, 0x02, 0x02, 0xFE, 0x00, 0x00, 0x00,
    //Git图标，占2个字符，安装在字符03、04位置
    0x00, 0x18, 0x24, 0x24, 0x18, 0x10, 0x10, 0x10,
    0x13, 0x1C, 0x10, 0x18, 0x24, 0x24 ,0x18, 0x00,
    0x00, 0x18, 0x24, 0x24, 0x18, 0x10, 0x20, 0xC0,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

char charsmap3[4 * 16] = {
    //旗标符号，占4个字符，安装位置从0xFB开始
    0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x07, 0x0F,
    0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80,
    0x80, 0x80, 0x80, 0x80, 0xE0, 0x00, 0x00, 0x00,
    //错误旗标
    0x00, 0x00, 0x00, 0x08, 0x05, 0x03, 0x07, 0x0F,
    0x01, 0x02, 0x04, 0x08, 0x03, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x88, 0x90, 0xA0, 0xC0, 0x80,
    0xC0, 0xA0, 0x90, 0x88, 0xE0, 0x00, 0x00, 0x00
};

char charsmap4[2 * 16] = {
    //两条细竖线，占2个字符，安装在0xB3、0xB4位置
    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
    0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
    0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01
};

char charsmap5[1 * 16] = {
    //阴影符号，占1个字符，安装在0xDC位置
    0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};

char charsmap6[20 * 16] = {
    //方格0~9的字符，每个方格占2个字符，安装位置从0x80位置开始
    //0
    0xFF, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xFF,
    0xFF, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
    0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0xFF,
    //1
    0x00, 0x00, 0x00, 0x01, 0x03, 0x07, 0x01, 0x01,
    0x01, 0x01, 0x01, 0x01, 0x07, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80,
    0x80, 0x80, 0x80, 0x80, 0xE0, 0x00, 0x00, 0x00,
    //2
    0x00, 0x00, 0x00, 0x07, 0x08, 0x0E, 0x0E, 0x00,
    0x00, 0x03, 0x04, 0x0F, 0x0F, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0xE0, 0x70, 0x30, 0x30, 0x60,
    0xC0, 0x10, 0x10, 0xF0, 0xE0, 0x00, 0x00, 0x00,
    //3
    0x00, 0x00, 0x00, 0x03, 0x04, 0x06, 0x00, 0x03,
    0x00, 0x00, 0x0C, 0x0C, 0x07, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0xC0, 0x60, 0x60, 0x40, 0x80,
    0x60, 0x30, 0x30, 0x60, 0xC0, 0x00, 0x00, 0x00,
    //4
    0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x08,
    0x10, 0x1F, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0,
    0xC0, 0xF0, 0xC0, 0xC0, 0xE0, 0x00, 0x00, 0x00,
    //5
    0x00, 0x00, 0x00, 0x07, 0x0F, 0x08, 0x08, 0x0F,
    0x00, 0x00, 0x0C, 0x08, 0x07, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0xE0, 0xE0, 0x00, 0x00, 0xC0,
    0x70, 0x30, 0x30, 0x60, 0xC0, 0x00, 0x00, 0x00,
    //6
    0x00, 0x00, 0x00, 0x01, 0x02, 0x06, 0x05, 0x0E,
    0x0C, 0x0C, 0x0C, 0x04, 0x03, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0xE0, 0x20, 0x00, 0xC0, 0x20,
    0x30, 0x30, 0x30, 0x20, 0xC0, 0x00, 0x00, 0x00,
    //7
    0x00, 0x00, 0x00, 0x07, 0x0F, 0x08, 0x00, 0x01,
    0x01, 0x01, 0x03, 0x03, 0x03, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0xF0, 0xE0, 0x40, 0x80, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    //8
    0x00, 0x00, 0x00, 0x07, 0x0C, 0x0C, 0x04, 0x03,
    0x04, 0x0C, 0x0C, 0x0C, 0x07, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0xE0, 0x30, 0x30, 0x20, 0xC0,
    0x20, 0x30, 0x30, 0x30, 0xE0, 0x00, 0x00, 0x00,
    //9
    0x00, 0x00, 0x00, 0x03, 0x04, 0x0C, 0x0C, 0x0C,
    0x04, 0x03, 0x00, 0x04, 0x07, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0xC0, 0x20, 0x30, 0x30, 0x30,
    0x70, 0xA0, 0x60, 0xC0, 0x00, 0x00, 0x00, 0x00
};
char charsmap7[2 * 16] = {
    //?号，占2个字符，安装在0xA7、0xA8位置
    0x00, 0x00, 0x00, 0x07, 0x08, 0x0C, 0x00, 0x00,
    0x01, 0x01, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x80, 0xC0, 0xC0, 0xC0, 0x80,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

//将字模写入显卡的字符发生器
void InstallChars()
{
    _BP = (int)&charsmap1;
    _CX = 4;     //4个字符
    _DX = 0xE;   //装入位置从0xE起
    _BL = 0;     //字符集0
    _BH = 16;    //字符高度
    _AX = 0x1100;//功能号
    geninterrupt(0x10);//int 10h

    _BP = (int)&charsmap2;
    _CX = 4;     //4个字符
    _DX = 1;     //装入位置从1起
    _AX = 0x1100;//功能号
    geninterrupt(0x10);//int 10h

    _BP = (int)&charsmap3;
    _CX = 4;     //4个字符
    _DX = 0xFB;  //装入位置
    _AX = 0x1100;//功能号
    geninterrupt(0x10);//int 10h

    _BP = (int)&charsmap4;
    _CX = 2;     //2个字符
    _DX = 0xB3;  //装入位置
    _AX = 0x1100;//功能号
    geninterrupt(0x10);//int 10h

    _BP = (int)&charsmap5;
    _DX = 0xDC;  //装入位置
    _AX = 0x1100;//功能号
    geninterrupt(0x10);//int 10h

    _BP = (int)&charsmap6;
    _CX = 20;    //20个字符
    _DX = 0x80;  //装入位置
    _AX = 0x1100;//功能号
    geninterrupt(0x10);//int 10h

    _BP = (int)&charsmap7;
    _CX = 2;     //2个字符
    _DX = 0xA7;  //装入位置
    _AX = 0x1100;//功能号
    geninterrupt(0x10);//int 10h
}

/*清除屏幕区域
  由left, top, right, bottom指定要更改的矩形区域
  color：区域的新颜色属性
*/
void ClearScreen(byte left, byte top, byte right, byte bottom, byte color)
{
    for (int y = top; y <= bottom; y++)
        for (int x = left; x <= right; x++)
        {
            VGAMemory[(y * SCREEN_WIDTH + x) * 2] = 0;
            VGAMemory[(y * SCREEN_WIDTH + x) * 2 + 1] = color;
        }
}

/*改变屏幕区域的显示颜色，不清除内容
  由left, top, right, bottom指定要更改的矩形区域
  color：区域的新颜色属性
*/
void ChangeColor(byte x, byte y, byte color)
{
    VGAMemory[(y * SCREEN_WIDTH + x) * 2 + 1] = color;
}
void ChangeColors(byte left, byte top, byte right, byte bottom, byte color)
{
    for (int y = top; y <= bottom; y++)
        for (int x = left; x <= right; x++)
            VGAMemory[(y * SCREEN_WIDTH + x) * 2 + 1] = color;
}

/*改变单个字符的颜色
  由x, y:屏幕坐标位置
  color：字符颜色（背景色不变）
*/
void ChangeFontColor(byte x, byte y, byte color)
{
    VGAMemory[(y * SCREEN_WIDTH + x) * 2 + 1] =
        (VGAMemory[(y * SCREEN_WIDTH + x) * 2 + 1] & 0xF0)
        | (color & 0xF);
}

/*改变单个字符的背景颜色
  由x, y:屏幕坐标位置
  color：背景颜色（字符色不变）
*/
void ChangeBGColor(byte x, byte y, byte color)
{
    VGAMemory[(y * SCREEN_WIDTH + x) * 2 + 1] =
        (VGAMemory[(y * SCREEN_WIDTH + x) * 2 + 1] & 0x0F)
        | (color << 4);
}

/*以直接写显示内存方式输出文字
  x, y:输出字符的起始位置
  text:要显示的文字
  len:指定输出文字的数量
*/
void PrintText(byte x, byte y, char* text)
{
    PrintTextLen(x, y, text, strlen(text));
}
void PrintTextLen(byte x, byte y, char* text, int len)
{
    int base = (y * SCREEN_WIDTH + x) * 2;
    for (byte i = 0; i < len; i++)
    {
        VGAMemory[base] = text[i];
        base += 2;
    }
}

/*以直接写显示内存方式重复输出字符
  x, y:输出字符的起始位置
  ch:要显示的字符
  count:重复次数
*/
void PrintChar(byte x, byte y, char ch, byte count)
{
    int base = (y * SCREEN_WIDTH + x) * 2;
    for (int i = 0; i < count; i++)
    {
        VGAMemory[base] = ch;
        base += 2;
    }
}